package cn.toutatis.sandbox.root.security.handler;

import cn.toutatis.common.config.ResultCode;
import cn.toutatis.common.result.Result;
import cn.toutatis.common.toolkit.ObjectToolkit;
import cn.toutatis.sandbox.root.security.authEntity.AccountEntity;
import cn.toutatis.sandbox.root.security.authEntity.JWTEntity;
import cn.toutatis.sandbox.root.security.constant.ValidationMessage;
import com.alibaba.fastjson.JSON;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author Toutatis_Gc
 *
 */
@Component
public class SecurityHandler implements AuthenticationSuccessHandler,AuthenticationFailureHandler, AuthenticationEntryPoint, AccessDeniedHandler {

    /**
     * 是否跳转页面
     * 从HttpServletRequest 获取的参数
     */
    private static final String REQUEST_PARAMETER_WHETHER_REDIRECT_PAGE = "REDIRECT_PAGE";

    /**
     * 自定义跳转页面
     */
    private static final String REQUEST_CUSTOM_REDIRECT_PAGE_MAPPING = "CUSTOM_REDIRECT_PAGE_MAPPING";

    /**
     * @see AuthenticationSuccessHandler
     * @throws IOException
     * @throws ServletException
     * 认证成功情况
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Object principal = authentication.getPrincipal();
        if (principal instanceof AccountEntity){
            System.err.println(666666666);
        }else if ( principal instanceof JWTEntity){

        }
        System.err.println(principal);

        Result result = new Result(false);
        result.setCode(ResultCode.AUTHENTICATION_SUCCESSFUL);
        result.setMessage(ResultCode.AUTHENTICATION_SUCCESSFUL);
        result.setSign(true);
        returnJson(response,result);
    }



    /**
     * @see AuthenticationFailureHandler
     * @throws IOException
     * @throws ServletException
     * 认证失败情况
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        Object encodeReturn = encodeReturn(request, response);
        Result result = new Result(false);
        String message;
        if (exception instanceof UsernameNotFoundException){
            message = exception.getMessage();
        }else if (exception instanceof BadCredentialsException){
            message = ResultCode.AUTHENTICATION_FAILED.getExtraInfo();
        }else {
            message = "内部错误";
        }
        result.setMessage(message);
        result.setCode(ResultCode.AUTHENTICATION_FAILED);
        returnJson(response,result);
    }

    /**
     * @see AuthenticationEntryPoint
     * @throws IOException
     * @throws ServletException
     * 匿名未认证处理
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        Result result = new Result(false);
        result.setCode(ResultCode.ANONYMITY_FAILED);
        result.setMessage(ResultCode.ANONYMITY_FAILED);
        returnJson(response,result);
    }

    /**
     * @throws IOException
     * @throws ServletException
     * @see AccessDeniedHandler
     * 认证成功访问，但没有权限
     */
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        Result result = new Result(false);
        result.setCode(ResultCode.PERMISSION_DEFINED_FAILED);
        result.setMessage(ResultCode.PERMISSION_DEFINED_FAILED);
        returnJson(response,result);
    }

    private Object encodeReturn(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        Object attribute = session.getAttribute(ValidationMessage.VALIDATION_SESSION_KEY);
        if (attribute != null){
            session.removeAttribute(ValidationMessage.VALIDATION_SESSION_KEY);
            if (attribute instanceof String){
                String value = String.valueOf(attribute);
                String forward = "forward:";
                if (value.startsWith(forward)){
                    String url = value.replace(forward, "");
                    request.getRequestDispatcher(url).forward(request,response);
                }
            }
        }
        encodeReturn(response);
        return attribute;
    }

    /**
     * @param response  response
     * @param o 序列化实体类
     * @throws IOException 流异常
     */
    private void returnJson(HttpServletResponse response,Object o) throws IOException {
        encodeReturn(response);
        response.getWriter().write(JSON.toJSONString(o));
    }

    /**
     * @param response response
     * 编码为application/json
     */
    private void encodeReturn(HttpServletResponse response){
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
    }

    private void jumpToPage(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        String whether = request.getParameter(REQUEST_PARAMETER_WHETHER_REDIRECT_PAGE);
        ObjectToolkit objectToolkit = ObjectToolkit.getInstance();
        if (objectToolkit.strNotBlank(whether) && ("true".equalsIgnoreCase(whether) || "false".equalsIgnoreCase(whether))){
            boolean whetherBool = Boolean.parseBoolean(whether);
            if (whetherBool){
                String pageMapping = request.getParameter(REQUEST_CUSTOM_REDIRECT_PAGE_MAPPING);
                if (objectToolkit.strIsBlank(pageMapping)){
                    request.getRequestDispatcher("/error").forward(request,response);
                }else {
                    request.getRequestDispatcher("/error").forward(request,response);
                }
            }
        }
    }


}
